


#include "wxSpeedButton.h"



IMPLEMENT_DYNAMIC_CLASS( wxSpeedButton, wxControl )

BEGIN_EVENT_TABLE(wxSpeedButton,wxControl)
    EVT_MOUSE_EVENTS ( wxSpeedButton::OnMouseEvents )
    EVT_PAINT        ( wxSpeedButton::OnPaint )
    EVT_SIZE         ( wxSpeedButton::OnSize )
    EVT_SET_FOCUS    ( wxSpeedButton::OnSetFocus )
    EVT_KILL_FOCUS   ( wxSpeedButton::OnKillFocus )
    EVT_CHAR         ( wxSpeedButton::OnKey )
END_EVENT_TABLE()




static  int             sbgCount    = 0;       
static  wxArrayPtrVoid  sbgArray;              


wxSpeedButton::~wxSpeedButton() {
int         n;




    n = sbgArray.Index((void *) this);
    if (n != wxNOT_FOUND) sbgArray.RemoveAt(n);

}



wxSpeedButton::wxSpeedButton( wxWindow     *inParent,          
                            wxWindowID      inID,              
                            const wxString &inLabel,           
                            const wxBitmap &inGlyph,           
                            int             inGlyphCount,      
                            int             inMargin,          
                            int             inGroupIndex,      
                            bool            inAllowAllUp,      
                            const wxPoint  &inPos,             
                            const wxSize   &inSize,            
                            long            inStyle,           
                            const wxValidator &inVal,          
                            const wxString &inName) {          

    Create( inParent, inID,
            inLabel,
            inGlyph, inGlyphCount, inMargin,
            inGroupIndex, inAllowAllUp,
            inPos, inSize, inStyle, inVal, inName);
}



wxSpeedButton::wxSpeedButton( wxWindow     *inParent,          
                            wxWindowID      inID,              
                            const wxString &inLabel,           
                            const wxString &inGlyphFile,       
                            int             inGlyphCount,      
                            int             inMargin,          
                            int             inGroupIndex,      
                            bool            inAllowAllUp,      
                            const wxPoint  &inPos,             
                            const wxSize   &inSize,            
                            long            inStyle,           
                            const wxValidator &inVal,          
                            const wxString &inName) {          
wxBitmap    bmp(inGlyphFile, wxBITMAP_TYPE_ANY );

    Create( inParent, inID,
            inLabel,
            bmp, inGlyphCount, inMargin,
            inGroupIndex, inAllowAllUp,
            inPos, inSize, inStyle, inVal, inName);
}




bool wxSpeedButton::Create( wxWindow       *inParent,          
                            wxWindowID      inID,              
                            const wxString &inLabel,           
                            const wxBitmap &inGlyph,           
                            int             inGlyphCount,      
                            int             inMargin,          
                            int             inGroupIndex,      
                            bool            inAllowAllUp,      
                            const wxPoint  &inPos,             
                            const wxSize   &inSize,            
                            long            inStyle,           
                            const wxValidator &inVal,          
                            const wxString &inName) {          

int         n;
wxString    name;
wxPoint     pos;
wxSize      size;
wxString    s;


    wxInitAllImageHandlers();


    sbgCount += 1;


    name = inName;
    name.Trim(true);
    name.Trim(false);
    if (name.Len() == 0) name.Printf(_T("SpeedButton-%d"), sbgCount);


    pos = inPos;
    if (pos.x < 0) pos.x = 0;
    if (pos.y < 0) pos.y = 0;


    size = inSize;
    size.SetDefaults(wxSize(72, 24));



    n = inStyle;
    n = n & (~ wxBORDER_MASK);
    n = n | wxBORDER_NONE;
    n = n | wxCLIP_CHILDREN;

    if (((n & wxBU_LEFT)   == 0) &&
        ((n & wxBU_TOP)    == 0) &&
        ((n & wxBU_RIGHT)  == 0) &&
        ((n & wxBU_BOTTOM) == 0))
            n = n | wxBU_LEFT;


    if (! wxControl::Create(inParent, inID, pos, size, n, inVal, name)) return false;


    wxControl::SetLabel(inLabel);
    wxControl::SetBackgroundColour(inParent->GetBackgroundColour());
    wxControl::SetForegroundColour(inParent->GetForegroundColour());
    wxControl::SetFont(inParent->GetFont());


    SplitGlyphs(inGlyph, inGlyphCount);


    mMargin = inMargin;
    if (mMargin < 0) mMargin = 0;


    mGroupIndex = inGroupIndex;
    mAllowAllUp = inAllowAllUp;


    mMouseDown     = false;
    mMouseOver     = false;
    mButtonDown    = false;
    mButtonFocused = false;


    mCalcBusy = false;


    mParent = GetParent();
    mTopParent = mParent;
    while ((mTopParent != NULL) && (! mTopParent->IsKindOf(CLASSINFO(wxTopLevelWindow))))
        mTopParent = mTopParent->GetParent();


    mUserData = 0;


    sbgArray.Add((void *) this);


    Refresh(false);


    return true;
}



void wxSpeedButton::SplitGlyphs(const wxBitmap &inBitmap, int inCount) {
int         n;
int         bw,bh;
int         sw,sh;
wxRect      rr;
wxImage     img;
wxBitmap    *bmp;


    mGlyphUp       = wxNullBitmap;
    mGlyphDown     = wxNullBitmap;
    mGlyphDisabled = wxNullBitmap;


    if (! inBitmap.Ok()) return;


    bw = inBitmap.GetWidth();
    bh = inBitmap.GetHeight();
    if ((bw <= 0) || (bh <= 0)) return;



    if      (inCount > 0) n = inCount;
    else if (bw >= bh)    n = (int) bw / bh;
    else                  n = (int) bh / bw;


    if (n == 1) {
        mGlyphUp   = inBitmap;
        mGlyphDown = inBitmap;

        img = inBitmap.ConvertToImage();
        img = img.ConvertToGreyscale();
        bmp = new wxBitmap(img);
        mGlyphDisabled = *bmp;
    }
    else if ((n == 2) && (bw >= bh)) {
        sw = (int) bw / n;
        sh = bh;

        rr.SetX(0);
        rr.SetY(0);
        rr.SetWidth(sw);
        rr.SetHeight(sh);
        mGlyphUp = inBitmap.GetSubBitmap(rr);
        mGlyphDown = inBitmap.GetSubBitmap(rr);
        rr.SetX(sw);
        mGlyphDisabled = inBitmap.GetSubBitmap(rr);
    }
    else if ((n == 2) && (bh > bw)) {
        sw = bw;
        sh = (int) bh / n;

        rr.SetX(0);
        rr.SetY(0);
        rr.SetWidth(sw);
        rr.SetHeight(sh);
        mGlyphUp = inBitmap.GetSubBitmap(rr);
        mGlyphDown = inBitmap.GetSubBitmap(rr);
        rr.SetY(sh);
        mGlyphDisabled = inBitmap.GetSubBitmap(rr);
    }
    else if ((n >= 3) && (bw >= bh)) {
        sw = (int) bw / n;
        sh = bh;

        rr.SetX(0);
        rr.SetY(0);
        rr.SetWidth(sw);
        rr.SetHeight(sh);
        mGlyphUp = inBitmap.GetSubBitmap(rr);
        rr.SetX(sw);
        mGlyphDown = inBitmap.GetSubBitmap(rr);
        rr.SetX(sw+sw);
        mGlyphDisabled = inBitmap.GetSubBitmap(rr);
    }
    else {
        sw = bw;
        sh = (int) bh / n;

        rr.SetX(0);
        rr.SetY(0);
        rr.SetWidth(sw);
        rr.SetHeight(sh);
        mGlyphUp = inBitmap.GetSubBitmap(rr);
        rr.SetY(sh);
        mGlyphDown = inBitmap.GetSubBitmap(rr);
        rr.SetY(sh+sh);;
        mGlyphDisabled = inBitmap.GetSubBitmap(rr);
    };


    MakeTransparent(mGlyphUp);
    MakeTransparent(mGlyphDown);
    MakeTransparent(mGlyphDisabled);
}



void wxSpeedButton::MakeTransparent(wxBitmap &inBitmap) {
int         h;
int         r,g,b;
wxImage     img;
wxBitmap    *bmp;


    if (! inBitmap.IsOk()) return;


    img = inBitmap.ConvertToImage();
    if (img.HasMask()) return;


    h = img.GetHeight();
    r = img.GetRed(0, h-1);
    b = img.GetBlue(0, h-1);
    g = img.GetGreen(0, h-1);


    img.SetMaskColour(r, g, b);


    bmp = new wxBitmap(img);
    inBitmap = *bmp;
}


void wxSpeedButton::GetGlyphSize(wxBitmap &inGlyph, int &outWidth, int &outHeight) {

    if (inGlyph.Ok()) {
        outWidth  = inGlyph.GetWidth();
        outHeight = inGlyph.GetHeight();
    }
    else {
        outWidth  = 0;
        outHeight = 0;
    };

}



wxSize wxSpeedButton::DoGetBestSize(void) {
int         i,n;
int         w,h;
int         bn;
int         bw, bh;
int         gw, gh;
int         lw, lh;


    bw = 0;
    bh = 0;
    GetGlyphSize(mGlyphUp, gw, gh);
        if (gw > bw) bw = gw;
        if (gh > bh) bh = gh;
    GetGlyphSize(mGlyphDown, gw, gh);
        if (gw > bw) bw = gw;
        if (gh > bh) bh = gh;
    GetGlyphSize(mGlyphDisabled, gw, gh);
        if (gw > bw) bw = gw;
        if (gh > bh) bh = gh;

    mGlyphSize.Set(bw, bh);


    lw = 0;
    lh = 0;
    if (! GetLabel().IsEmpty()) GetTextExtent(GetLabel(), &lw, &lh);

    mLabelSize.Set(lw, lh);



    bn = 2;


    i = GetWindowStyleFlag();

    if (((i & wxBU_LEFT) != 0) || ((i & wxBU_RIGHT) != 0)) {
        w = bn + mMargin + bw + mMargin + lw + mMargin + bn;
        n = (bh > lh) ? bh : lh;
        h = bn + mMargin + n + mMargin + bn;
    }
    else if (((i & wxBU_TOP) != 0) || ((i & wxBU_BOTTOM) != 0)) {
        n = (bw > lw) ? bw : lw;
        w = bn + mMargin + n + mMargin + bn;
        h = bn + mMargin + bh + mMargin + lh + mMargin + bn;
    }
    else {
        w = bn + mMargin + bw + mMargin + lw + mMargin + bn;
        n = (bh > lh) ? bh : lh;
        h = bn + mMargin + n + mMargin + bn;
    };

    mBestSize.Set(w, h);


    return mBestSize;
}



void wxSpeedButton::CalcLayout(bool inRefresh) {
int         i;
int         bn;
int         w, h;
bool        gz, lz;
int         gx, gy;
int         lx, ly;


    if (mCalcBusy) return;
    mCalcBusy = true;


    GetSize(&w,&h);
    mCurrentSize.Set(w, h);


    DoGetBestSize();


    gz = (mGlyphSize.GetWidth() == 0) || (mGlyphSize.GetHeight() == 0);
    lz = (mLabelSize.GetWidth() == 0) || (mLabelSize.GetHeight() == 0);



    bn = 2;


    i = GetWindowStyleFlag();

    if (gz && lz) {                
        gx = 0;
        gy = 0;
        lx = 0;
        ly = 0;
    }
    else if (gz) {                 
        gx = 0;
        gy = 0;
        lx = (mCurrentSize.GetWidth()  - mLabelSize.GetWidth())  / 2;
        ly = (mCurrentSize.GetHeight() - mLabelSize.GetHeight()) / 2;
    }
    else if (lz) {                 
        gx = (mCurrentSize.GetWidth()  - mGlyphSize.GetWidth())  / 2;
        gy = (mCurrentSize.GetHeight() - mGlyphSize.GetHeight()) / 2;
        lx = 0;
        ly = 0;
    }
    else if ((i & wxBU_LEFT) != 0) {
        gx = bn + mMargin;
        lx = gx + mGlyphSize.GetWidth() + mMargin;
        gy = (mCurrentSize.GetHeight() - mGlyphSize.GetHeight()) / 2;
        ly = (mCurrentSize.GetHeight() - mLabelSize.GetHeight()) / 2;
    }
    else if ((i & wxBU_RIGHT) != 0) {
        gx = mCurrentSize.GetWidth() - (mGlyphSize.GetWidth() + mMargin + bn);
        lx = gx - (mLabelSize.GetWidth() + mMargin);
        gy = (mCurrentSize.GetHeight() - mGlyphSize.GetHeight()) / 2;
        ly = (mCurrentSize.GetHeight() - mLabelSize.GetHeight()) / 2;
    }
    else if ((i & wxBU_TOP) != 0) {
        gx = (mCurrentSize.GetWidth()  - mGlyphSize.GetWidth())  / 2;
        lx = (mCurrentSize.GetWidth()  - mLabelSize.GetWidth())  / 2;
        gy = bn + mMargin;
        ly = gy + mMargin + mGlyphSize.GetHeight();
    }
    else if ((i & wxBU_BOTTOM) != 0) {
        gx = (mCurrentSize.GetWidth()  - mGlyphSize.GetWidth())  / 2;
        lx = (mCurrentSize.GetWidth()  - mLabelSize.GetWidth())  / 2;
        gy = mCurrentSize.GetHeight() - (bn + mMargin + mGlyphSize.GetHeight());
        ly = gy - (mLabelSize.GetHeight() + mMargin);
    }
    else {
        gx = 0;
        gy = 0;
        lx = 0;
        ly = 0;
    };


    mGlyphPos.x = gx;
    mGlyphPos.y = gy;
    mLabelPos.x = lx;
    mLabelPos.y = ly;


    if (inRefresh) Refresh(false);


    mCalcBusy = false;
}






void wxSpeedButton::SetLabel(wxString &inLabel) {
    wxControl::SetLabel(inLabel);
    Refresh(false);
}


void    wxSpeedButton::SetGlyphUp(wxBitmap &inBitmap) {

    mGlyphUp = inBitmap;
    Refresh(false);
}

wxBitmap    &wxSpeedButton::GetGlyphUp(void) {

    return mGlyphUp;
}


void    wxSpeedButton::SetGlyphDown(wxBitmap &inBitmap) {

    mGlyphDown = inBitmap;
    Refresh(false);
}

wxBitmap    &wxSpeedButton::GetGlyphDown(void) {

    return mGlyphDown;
}


void    wxSpeedButton::SetGlyphDisabled(wxBitmap &inBitmap) {

    mGlyphDisabled = inBitmap;
    Refresh(false);
}

wxBitmap    &wxSpeedButton::GetGlyphDisabled(void) {

    return mGlyphDisabled;
}





void    wxSpeedButton::SetAlign(int inAlign) {
int     i,n;


    n = inAlign;
    if ((n != wxBU_LEFT) && (n != wxBU_TOP) &&(n != wxBU_RIGHT) &&(n != wxBU_BOTTOM)) n = wxBU_LEFT;


    i = GetWindowStyleFlag();


    i = i & (~ wxBORDER_MASK);
    i = i & (~ wxBU_ALIGN_MASK);


    i = i | wxBORDER_NONE;
    i = i | n;
    i = i | wxCLIP_CHILDREN;


    SetWindowStyleFlag(i);
    Refresh(false);
}

int     wxSpeedButton::GetAlign(void) {
int     i;

    i = GetWindowStyleFlag();
    i = i & wxBU_ALIGN_MASK;

    return i;
}


void    wxSpeedButton::SetMargin(int inMargin) {

    mMargin = inMargin;
    Refresh(false);
}

int     wxSpeedButton::GetMargin(void) {

    return mMargin;
}


void    wxSpeedButton::SetGroupIndex(bool inIndex) {

    mGroupIndex = inIndex;
    Refresh(false);
}

int     wxSpeedButton::GetGroupIndex(void) {

    return mGroupIndex;
}




void    wxSpeedButton::SetDown(bool inDown) {


    if (mGroupIndex == 0) {
        mButtonDown = false;
    }


    else if (mGroupIndex == -1) {
        mButtonDown = inDown;
    }


    else if (mGroupIndex == -2) {
        SetAllUp(this);
        if ((! inDown) && (mAllowAllUp)) mButtonDown = false;
        else                             mButtonDown = true;
    }


    else {
        SetAllUp(this);
        if ((! inDown) && (mAllowAllUp)) mButtonDown = false;
        else                             mButtonDown = true;
    };


    Refresh(false);
}

bool    wxSpeedButton::GetDown(void) {

    return mButtonDown;
}

void    wxSpeedButton::SetAllUp(wxSpeedButton *inButton) {
int             i,n;
wxSpeedButton   *b;


    if (inButton == NULL) return;


    if (inButton->mGroupIndex == 0) {
        inButton->mButtonDown = false;
        inButton->Refresh(false);
    }


    else if (inButton->mGroupIndex == -1) {
        inButton->mButtonDown = false;
        inButton->Refresh(false);
    }


    else if (inButton->mGroupIndex == -2) {
        n = sbgArray.GetCount();
        for(i=0; i<n; i++) {
            b = (wxSpeedButton *) sbgArray.Item(i);
            if (b->mParent == inButton->mParent) {
                b->mButtonDown = false;
                b->Refresh(false);
            };
        };
    }


    else {
        n = sbgArray.GetCount();
        for(i=0; i<n; i++) {
            b = (wxSpeedButton *) sbgArray.Item(i);
            if ((b->mGroupIndex == inButton->mGroupIndex) && (b->mTopParent == inButton->mTopParent)) {
                b->mButtonDown = false;
                b->Refresh(false);
            };
        };
    };


}

void    wxSpeedButton::SetValue(bool inDown) {

    SetDown(inDown);
}

bool    wxSpeedButton::GetValue(void) {

    return GetDown();
}


void    wxSpeedButton::SetAllowAllUp(bool inAllUp) {

    mAllowAllUp = inAllUp;
    Refresh(false);
}

bool    wxSpeedButton::GetAllowAllUp(void) {

    return mAllowAllUp;
}


void    wxSpeedButton::SetUserData(long inData) {

    mUserData = inData;
}

long    wxSpeedButton::GetUserData(void) {

    return mUserData;
}








void wxSpeedButton::OnMouseEvents(wxMouseEvent& event) {
wxWindow    *win;


    win = (wxWindow *) this;


    if (event.LeftDown() || event.RightDown()) {
       if (!HasCapture()) CaptureMouse();
        mMouseDown = true;
        mButtonFocused = true;
        win->SetFocus();
        Redraw();
    }



    else if (event.LeftUp() || event.RightUp()) {
        if (HasCapture()) ReleaseMouse();
        mMouseDown = false;
        mButtonFocused = true;
        win->SetFocus();
        SetDown(! mButtonDown);
        SendEvent(event.LeftUp());
        Redraw();
    }


    else if (event.Entering()) {
        mMouseOver = true;
        Redraw();
    }
    else if (event.Leaving()) {
        mMouseOver = false;
        Redraw();
    };
}



void wxSpeedButton::DoClick(bool inLeft) {

    SetDown(! mButtonDown);
    SendEvent(inLeft);
    Refresh(false);
}




void wxSpeedButton::SendEvent(bool inLeft) {
int                 n;
long                now;
wxCommandEvent      event;


    if (inLeft) event.SetEventType(wxEVT_COMMAND_LEFT_CLICK);
    else        event.SetEventType(wxEVT_COMMAND_RIGHT_CLICK);

    event.SetId(GetId());


    event.SetEventObject(this);


    n = inLeft ? 1 : 0;
    event.SetInt(n);


    now = (long) wxDateTime::GetTimeNow();
    event.SetTimestamp(now);


    GetEventHandler()->ProcessEvent(event);
}



void wxSpeedButton::OnPaint(wxPaintEvent& event) {
    wxPaintDC dc(this);
    Paint(dc);
    event.Skip();
}


void wxSpeedButton::Redraw() {
    wxClientDC dc(this);
    Paint(dc);
}



void    wxSpeedButton::Paint( wxDC &dc ) {
int         n;
int         w,h;
wxColour    cf;                    
wxColour    cb;                    
wxColour    cg;                    
wxColour    cy;                    
wxBrush     bb;                    
wxPen       pp;                    
wxBitmap    bmp;
wxString    s;
wxRect      rr;


    if (! mCalcBusy) CalcLayout(false);

    w = mCurrentSize.GetWidth();
    h = mCurrentSize.GetHeight();


    cf = GetForegroundColour();
    cb = GetBackgroundColour();
    cg = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT );
    cy = wxTheColourDatabase->Find(_("YELLOW"));


    rr.SetX(0);
    rr.SetY(0);
    rr.SetWidth(w);
    rr.SetHeight(h);

    n = 0;
    if (mMouseDown || mButtonDown) n = n | wxCONTROL_PRESSED;
    if (mButtonFocused) n = n | wxCONTROL_ISDEFAULT;

    wxRendererNative::Get().DrawPushButton(this, dc, rr, n);


    pp = *wxBLACK_PEN;
    pp.SetColour(cy);
//  pp.SetStyle(wxDOT);
    dc.SetPen(pp);
    if (mMouseOver) {
        n = 2;
        dc.DrawLine(  n,   n, w-n,   n);
        dc.DrawLine(w-n,   n, w-n, h-n);
        dc.DrawLine(w-n, h-n,   n, h-n);
        dc.DrawLine(  n, h-n,   n,   n);
    };


    if      (! IsEnabled())             bmp = mGlyphDisabled;
    else if (mMouseDown || mButtonDown) bmp = mGlyphDown;
    else                                bmp = mGlyphUp;

    if (bmp.IsOk()) dc.DrawBitmap(bmp, mGlyphPos.x, mGlyphPos.y, true );


    s = GetLabelText();
    if (! s.IsEmpty()) {
        dc.SetFont(GetFont());
        dc.SetBackgroundMode(wxTRANSPARENT);
        if (! IsEnabled()) dc.SetTextForeground(cg);
        else               dc.SetTextForeground(cf);
        dc.DrawText(s, mLabelPos.x, mLabelPos.y);
    };
}


void wxSpeedButton::OnSize( wxSizeEvent &event ) {
    Refresh(false);
    event.Skip();
}




void wxSpeedButton::OnSetFocus(wxFocusEvent& event) {

    mButtonFocused = true;
    Redraw();
    event.Skip();
}


void wxSpeedButton::OnKillFocus(wxFocusEvent& event) {

    mButtonFocused = false;
    Redraw();
    event.Skip();
}


void wxSpeedButton::OnKey(wxKeyEvent& event) {
int         n;
wxString    s;

    n = event.GetKeyCode();
    if ((n == '\n') || ( n == '\r') || (n == ' ')) {
        mButtonFocused = true;
        SetDown(! mButtonDown);
        SendEvent(true);
        Redraw();
//Refresh(false);
    };

    event.Skip();
}








